﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.Serialization;
using System.Threading;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Markup;
using GurLoader;
using GurLoader.GlobalHotkey;
using GurLoader.Preferences;
using GurLoader.Service.ScreenshotUpload;
using GurLoader.View;
using Moq;
using NUnit.Framework;
using GurLoader.Service.HotKeyManager;

namespace GurLoaderWPF.Test.Service.HotKeyManager
{
    [TestFixture]
    public class HotKeyManagerTests
    {
        [Test]
        public void CreateInstanceWithHotkeyHostTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            var hkManager = new HotKeyManagerService(
                prefs, 
                mockDispatcher.Object, 
                mockScreenshotUploadService.Object, 
                mockHotKeyHost.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        public void CreateInstanceWithViewBuilderTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x=>x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x=>x.GetHwndSource( mockHiddenHotkeyWindow.Object )).Returns(mockHwndSource.Object ).Verifiable();

            mockHwndSource.Setup(x=>x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockViewBuilder.Object,
                mockHwndSourceFactory.Object,
                mockHotkeyProvider.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithViewBuilderNullPreferencesTest()
        {
            GurLoaderPreferences prefs = null;
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x => x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x => x.GetHwndSource(mockHiddenHotkeyWindow.Object)).Returns(mockHwndSource.Object).Verifiable();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockViewBuilder.Object,
                mockHwndSourceFactory.Object,
                mockHotkeyProvider.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithViewBuilderNullDispatcherTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x => x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x => x.GetHwndSource(mockHiddenHotkeyWindow.Object)).Returns(mockHwndSource.Object).Verifiable();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                null,
                mockScreenshotUploadService.Object,
                mockViewBuilder.Object,
                mockHwndSourceFactory.Object,
                mockHotkeyProvider.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithViewBuilderNullSsUploadTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x => x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x => x.GetHwndSource(mockHiddenHotkeyWindow.Object)).Returns(mockHwndSource.Object).Verifiable();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                null,
                mockViewBuilder.Object,
                mockHwndSourceFactory.Object,
                mockHotkeyProvider.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithViewBuilderNullViewBuilderTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x => x.GetHwndSource(mockHiddenHotkeyWindow.Object)).Returns(mockHwndSource.Object).Verifiable();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                null,
                mockHwndSourceFactory.Object,
                mockHotkeyProvider.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithViewBuilderNullHwndSourceFactoryTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x => x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockViewBuilder.Object,
                null,
                mockHotkeyProvider.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithViewBuilderNullHotkeyProviderTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x => x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x => x.GetHwndSource(mockHiddenHotkeyWindow.Object)).Returns(mockHwndSource.Object).Verifiable();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockViewBuilder.Object,
                mockHwndSourceFactory.Object,
                null);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithHotkeyHostNullPrefsTest()
        {
            GurLoaderPreferences prefs = null;
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithHotkeyHostNullDispatcherTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            var hkManager = new HotKeyManagerService(
                prefs,
                null,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            Assert.IsNotNull(hkManager);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithHotkeyHostNullSSUploadTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                null,
                mockHotKeyHost.Object);
        }

        [Test]
        [ExpectedException(typeof(ArgumentNullException))]
        public void CreateInstanceWithHotkeyHostNullHkHostTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                (IHotKeyHost) null);
        }

        [Test]
        public void CreateBindingsForFullScreenCaptureTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.FullScreenCaptureEnabled = true;
            prefs.FullScreenCaptureKey = Key.C;
            prefs.FullScreenCaptureModifierKeys = ModifierKeys.Alt;

            prefs.AreaScreenCaptureEnabled = false;

            mockHotKeyHost.Setup(x=>x.AddHotKey(
                new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>() ) ) ).Verifiable();
            
            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();
            Assert.IsNotNull(hkManager);

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                        new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>())), 
                    Times.Once);

            mockHotKeyHost.VerifyAll();
            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }

        [Test]
        public void CreateBindingsForAreaScreenCaptureTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.AreaScreenCaptureEnabled = true;
            prefs.AreaScreenCaptureKey = Key.A;
            prefs.AreaScreenCaptureModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            prefs.FullScreenCaptureEnabled = false;

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>()))).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();
            Assert.IsNotNull(hkManager);

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                        new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>())),
                    Times.Once);

            mockHotKeyHost.VerifyAll();
            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }

        [Test]
        public void RemoveBindingsTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.AreaScreenCaptureEnabled = true;
            prefs.AreaScreenCaptureKey = Key.A;
            prefs.AreaScreenCaptureModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            prefs.FullScreenCaptureEnabled = true;
            prefs.FullScreenCaptureKey = Key.C;
            prefs.FullScreenCaptureModifierKeys = ModifierKeys.Alt;


            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>()))).Verifiable();

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>()))).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();

            mockHotKeyHost.Setup( x => x.HotKeys ).Returns(
                new [] { new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true ),
                            new HotKey(Key.C, ModifierKeys.Alt, true) } ).Verifiable();

            Assert.IsNotNull(hkManager);

            hkManager.RemoveBindings();

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                        new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>())),
                    Times.Once);

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                    new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>())),
                Times.Once);

            mockHotKeyHost.Verify(
                x => x.RemoveHotKey(
                        new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>())),
                    Times.Once);

            mockHotKeyHost.Verify(
                x => x.RemoveHotKey(
                    new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>())),
                Times.Once);

            mockHotKeyHost.VerifyAll();
            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }

        private class FakeHotKey : HotKey
        {
            public FakeHotKey()
            {
            }

            public FakeHotKey(Key key, ModifierKeys modifiers) : base(key, modifiers)
            {
            }

            public FakeHotKey(Key key, ModifierKeys modifiers, bool enabled) : base(key, modifiers, enabled)
            {
            }

            public FakeHotKey(Key key, ModifierKeys modifiers, Action action) : base(key, modifiers, action)
            {
            }

            public FakeHotKey(Key key, ModifierKeys modifiers, bool enabled, Action action) : base(key, modifiers, enabled, action)
            {
            }

            protected FakeHotKey(SerializationInfo info, StreamingContext context) : base(info, context)
            {
            }

            public void RaisePressEvent()
            {
                RaiseOnHotKeyPressed();
            }
        }

        [Test]
        public void FullScreenCaptureExecTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.AreaScreenCaptureEnabled = false;

            prefs.FullScreenCaptureEnabled = true;
            prefs.FullScreenCaptureKey = Key.C;
            prefs.FullScreenCaptureModifierKeys = ModifierKeys.Alt;

            List<HotKey> hotKeysAdded = new List<HotKey>();

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>())))
                .Callback<HotKey>( hotKeysAdded.Add )
                .Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();

            ManualResetEvent mre = new ManualResetEvent(false);
            mockScreenshotUploadService.Setup(x => x.UploadFullScreen()).Callback(
                () => mre.Set()).Verifiable();

            foreach (var binding in hotKeysAdded)
            {
                binding.OnPressedAction.Invoke();
            }

            bool mreSet = mre.WaitOne(1000*3);
            if ( ! mreSet )
                Assert.Fail("Timeout waiting for reset event.");

            mockHotKeyHost.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }

        [Test]
        public void AreaScreenCaptureExecTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.FullScreenCaptureEnabled = false;

            prefs.AreaScreenCaptureEnabled = true;
            prefs.AreaScreenCaptureKey = Key.A;
            prefs.AreaScreenCaptureModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            List<HotKey> hotKeysAdded = new List<HotKey>();

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>())))
                .Callback<HotKey>(hotKeysAdded.Add).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();

            ManualResetEvent mre = new ManualResetEvent(false);
            mockScreenshotUploadService.Setup(x => x.UploadScreenArea(It.IsAny<IDispatcher>(), true)).Callback(
                () => mre.Set()).Verifiable();

            foreach (var binding in hotKeysAdded)
            {
                binding.OnPressedAction.Invoke();
            }

            bool mreSet = mre.WaitOne(1000 * 3);
            if (!mreSet)
                Assert.Fail("Timeout waiting for reset event.");

            mockHotKeyHost.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }

        [Test]
        public void DisposeTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.FullScreenCaptureEnabled = false;

            prefs.AreaScreenCaptureEnabled = true;
            prefs.AreaScreenCaptureKey = Key.A;
            prefs.AreaScreenCaptureModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>()))).Verifiable();

            mockHotKeyHost.As<IDisposable>().Setup(x=>x.Dispose()).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();

            hkManager.Dispose();

            mockHotKeyHost.As<IDisposable>().Verify(x => x.Dispose(), Times.Once);

            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
            mockHotKeyHost.VerifyAll();
        }

        [Test]
        public void DisposeWithWindowTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IViewBuilder> mockViewBuilder = new Mock<IViewBuilder>();

            Mock<IWindow> mockHiddenHotkeyWindow = new Mock<IWindow>();
            mockViewBuilder.Setup(x => x.CreateHotkeyWindow(It.IsAny<bool>())).Returns(mockHiddenHotkeyWindow.Object).Verifiable();

            Mock<IHwndSourceFactory> mockHwndSourceFactory = new Mock<IHwndSourceFactory>();
            Mock<IHwndSource> mockHwndSource = new Mock<IHwndSource>();
            mockHwndSourceFactory.Setup(x => x.GetHwndSource(mockHiddenHotkeyWindow.Object)).Returns(mockHwndSource.Object).Verifiable();

            mockHwndSource.Setup(x => x.AddHook(It.IsAny<HwndSourceHook>())).Verifiable();

            Mock<IWindowsHotkeyProvider> mockHotkeyProvider = new Mock<IWindowsHotkeyProvider>();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockViewBuilder.Object,
                mockHwndSourceFactory.Object,
                mockHotkeyProvider.Object);

            hkManager.Dispose();

            mockHiddenHotkeyWindow.Verify(x => x.CloseWindow(), Times.Once);
            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }

        [Test]
        public void MultiDisposeTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.FullScreenCaptureEnabled = false;

            prefs.AreaScreenCaptureEnabled = true;
            prefs.AreaScreenCaptureKey = Key.A;
            prefs.AreaScreenCaptureModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>()))).Verifiable();

            mockHotKeyHost.As<IDisposable>().Setup(x => x.Dispose()).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();

            hkManager.Dispose();
            hkManager.Dispose();

            mockHotKeyHost.As<IDisposable>().Verify(x => x.Dispose(), Times.Once);

            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
            mockHotKeyHost.VerifyAll();
        }

        [Test]
        public void PreferencesChangedTest()
        {
            GurLoaderPreferences prefs = new GurLoaderPreferences();
            Mock<IDispatcher> mockDispatcher = new Mock<IDispatcher>();
            Mock<IScreenshotUploadService> mockScreenshotUploadService = new Mock<IScreenshotUploadService>();
            Mock<IHotKeyHost> mockHotKeyHost = new Mock<IHotKeyHost>();

            prefs.AreaScreenCaptureEnabled = true;
            prefs.AreaScreenCaptureKey = Key.A;
            prefs.AreaScreenCaptureModifierKeys = ModifierKeys.Alt | ModifierKeys.Control;

            prefs.FullScreenCaptureEnabled = true;
            prefs.FullScreenCaptureKey = Key.C;
            prefs.FullScreenCaptureModifierKeys = ModifierKeys.Alt;


            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>()))).Verifiable();

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>()))).Verifiable();

            mockHotKeyHost.Setup(x => x.AddHotKey(
                new HotKey(Key.J, ModifierKeys.Alt, true, It.IsAny<Action>()))).Verifiable();

            var hkManager = new HotKeyManagerService(
                prefs,
                mockDispatcher.Object,
                mockScreenshotUploadService.Object,
                mockHotKeyHost.Object);

            hkManager.CreateBindings();

            mockHotKeyHost.Setup(x => x.HotKeys).Returns(
                new[] { new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true ),
                            new HotKey(Key.C, ModifierKeys.Alt, true) }).Verifiable();

            Assert.IsNotNull(hkManager);

            prefs.FullScreenCaptureKey = Key.J;
            prefs.Save();

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                        new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>())),
                    Times.Exactly(2));

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                    new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>())),
                Times.Once);

            mockHotKeyHost.Verify(
                x => x.AddHotKey(
                    new HotKey(Key.J, ModifierKeys.Alt, true, It.IsAny<Action>())),
                Times.Once);

            mockHotKeyHost.Verify(
                x => x.RemoveHotKey(
                        new HotKey(Key.A, ModifierKeys.Alt | ModifierKeys.Control, true, It.IsAny<Action>())),
                    Times.Once);

            mockHotKeyHost.Verify(
                x => x.RemoveHotKey(
                    new HotKey(Key.C, ModifierKeys.Alt, true, It.IsAny<Action>())),
                Times.Once);

            mockHotKeyHost.VerifyAll();
            mockDispatcher.VerifyAll();
            mockScreenshotUploadService.VerifyAll();
        }
    }
}
